#include "includes.h"


struct global_history history;
int state;
struct msg_view_change vc_list;
struct msg_prepare_ok prep_ok_list;
struct msg_client_update update_queue;
struct msg_client_update pending_updates;
struct client_ts last_executed;
struct client_ts last_enqueued;
struct msg_prepare *prep;
extern int host_count;
int local_aru;
extern int my_id;
int last_attempted;
int last_installed;
int last_proposed;

void init_ds() {

	init_host_list();
	
	INIT_LIST_HEAD(&vc_list.list);
	INIT_LIST_HEAD(&prep_ok_list.list);
	INIT_LIST_HEAD(&history.list);
	INIT_LIST_HEAD(&update_queue.list);
	INIT_LIST_HEAD(&pending_updates.list);
	INIT_LIST_HEAD(&last_executed.list);
	INIT_LIST_HEAD(&last_enqueued.list);
	last_attempted = -1;
	last_proposed = -1;
	last_installed = -1;
	local_aru = -1;
}

struct msg_view_change *create_view_change(int server_id, int attempted) {
	struct msg_view_change *msg;
	msg = (struct msg_view_change *) malloc(sizeof(struct msg_view_change));
	msg->server_id = server_id;
	msg->attempted = attempted;
	
	return msg;
}

char *serialize_view_change(struct msg_view_change *vc) {
	char *msg;
	int len = 2 * INT_SIZE + strlen(TITLE_VC) + 4;
	//allocating 4 chars for each integer
	
	msg = (char *) malloc(len); 
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:%d", TITLE_VC, vc->server_id, vc->attempted); 
	
	return msg;
}

struct msg_view_change *deserialize_view_change(char *vc) {
	char *tmp;
	struct msg_view_change *msg;
	char* vc_cpy;
	//First make a copy
	vc_cpy = (char *) malloc(strlen(vc) + 1);
	bzero((char *) vc_cpy, strlen(vc) + 1);
	strncpy(vc_cpy, vc, strlen(vc));

	tmp = strtok(vc_cpy, ":");
	tmp = strtok(NULL, ":"); 

	msg = (struct msg_view_change *) malloc(sizeof(struct msg_view_change));
	msg->server_id = atoi(tmp);
	msg->attempted = atoi(strtok(NULL, ":"));
	
	free(vc_cpy);
	
	return msg;
}

struct msg_client_update *create_client_update(int client, int server, int timestamp, char *update) {
	struct msg_client_update *msg;
	msg = (struct msg_client_update *) malloc(sizeof(struct msg_client_update));
	
	msg->client_id = client;
	msg->server_id = server;
	msg->timestamp = timestamp;

	msg->update = (char *)malloc(strlen(update) + 1);
	bzero((char *) msg->update, strlen(update) + 1);
	
	strncpy(msg->update, update, strlen(update));
	
	return msg;
}
char *serialize_client_update(struct msg_client_update *cu) {
	int len = 0;
	char *msg;
	
	len = 3*INT_SIZE + strlen(cu->update) + strlen(TITLE_CU) + 4 + 1;
	msg = (char *) malloc(len);
	bzero((char *)msg, len);
	
	sprintf(msg, "%s:%d:%d:%d:%s", TITLE_CU, cu->client_id, cu->server_id, cu->timestamp, cu->update);
	
	return msg;
}
struct msg_client_update *deserialize_client_update(char *_cu) {
	struct msg_client_update *msg;
	char *tmp;
	char *cu;
	
	cu = (char *) malloc(strlen(_cu) + 1);
	bzero((char *) cu, strlen(_cu) + 1);
	strncpy(cu, _cu, strlen(_cu));	
	
	msg = (struct msg_client_update *) malloc(sizeof(struct msg_client_update));
	
	strtok(cu, ":");
	msg->client_id = atoi(strtok(NULL, ":"));
	msg->server_id = atoi(strtok(NULL, ":"));
	msg->timestamp = atoi(strtok(NULL, ":"));
	
	tmp = strtok(NULL, ":");
	msg->update = (char *)malloc(strlen(tmp) + 1);
	bzero((char*)msg->update,strlen(tmp) + 1);
	strncpy(msg->update, tmp, strlen(tmp));
	
	free(cu);
	
	return msg;	
}


struct msg_vc_proof *create_vc_proof(int server_id, int installed) {
	struct msg_vc_proof *msg;
	msg = (struct msg_vc_proof *) malloc(sizeof(struct msg_vc_proof));
	
	msg->server_id = server_id;
	msg->installed = installed;
	
	return msg;
}

char *serialize_vc_proof(struct msg_vc_proof *vc_proof) {
	char *msg;
	int len = 2 * INT_SIZE + strlen(TITLE_VC_PROOF) + 4;
	//allocating 4 chars for each integer
	
	msg = (char *) malloc(len); 
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:%d", TITLE_VC_PROOF, vc_proof->server_id, vc_proof->installed); 
	
	return msg;
}

struct msg_vc_proof *deserialize_vc_proof(char *_vc_proof) {
	char *tmp;
	char *vc_proof;
	
	vc_proof = (char *) malloc(strlen(_vc_proof) + 1);
	bzero((char *) vc_proof, strlen(_vc_proof) + 1);
	strncpy(vc_proof, _vc_proof, strlen(_vc_proof));
	
	struct msg_vc_proof *msg;

	tmp = strtok(vc_proof, ":");
	tmp = strtok(NULL, ":"); 

	msg = (struct msg_vc_proof *) malloc(sizeof(struct msg_vc_proof));
	msg->server_id = atoi(tmp);
	msg->installed = atoi(strtok(NULL, ":"));
	
	free(vc_proof);
	
	return msg;
}

struct msg_prepare *create_prepare(int server_id, int view, int local_aru) {
	struct msg_prepare *msg;
	msg = (struct msg_prepare *) malloc(sizeof(struct msg_prepare));
	
	msg->server_id = server_id;
	msg->view = view;
	msg->local_aru = local_aru;
	
	return msg;
}

char *serialize_prepare(struct msg_prepare *prep) {
	char *msg;
	int len = 3 * INT_SIZE + strlen(TITLE_PREP) + 4;
	//allocating 4 chars for each integer
	
	msg = (char *) malloc(len); 
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:%d:%d", TITLE_PREP, prep->server_id, prep->view, prep->local_aru); 
	
	return msg;
}

struct msg_prepare *deserialize_prepare(char *_prep) {
	char *tmp;
	char *prep;
	struct msg_prepare *msg;
		
	prep = (char *) malloc(strlen(_prep) + 1);
	bzero((char *) prep, strlen(_prep) + 1);
	strncpy(prep, _prep, strlen(_prep));	
	
	tmp = strtok(prep, ":");
	tmp = strtok(NULL, ":"); 

	msg = (struct msg_prepare *) malloc(sizeof(struct msg_prepare));
	msg->server_id = atoi(tmp);
	msg->view = atoi(strtok(NULL, ":"));
	msg->local_aru = atoi(strtok(NULL, ":"));
	
	free(prep);
	
	return msg;
}

struct msg_proposal *create_proposal(int server_id, int view, int seq, char *update) {
	struct msg_proposal *msg;
	
	msg = (struct msg_proposal *) malloc(sizeof(struct msg_proposal));
	msg->server_id = server_id;
	msg->view = view;
	msg->seq = seq;
	msg->update = (char *) malloc(strlen(update)+1);
	bzero((char*) msg->update, strlen(update)+1);
	strncpy(msg->update, update, strlen(update));
	
	return msg;
}

char *serialize_proposal(struct msg_proposal *prop) {
	char *msg;
	int len = 3 * INT_SIZE + strlen(TITLE_PROP) + strlen(prop->update) + 5;
	//allocating 4 chars for each integer
	
	//DEBUGPRINT("Reached Proposal Serialization\n",NULL);
	
	msg = (char *) malloc(len); 
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:%d:%d:%s", TITLE_PROP, prop->server_id, 
			prop->view, prop->seq, prop->update); 
	return msg;
}

struct msg_proposal *deserialize_proposal(char *_prop) {
	struct msg_proposal *msg;
	char *tmp;
	char *prop;
	msg = (struct msg_proposal *) malloc(sizeof(struct msg_proposal));
	
	prop = (char *) malloc(strlen(_prop) + 1);
	bzero((char *) prop, strlen(_prop) + 1);
	strncpy(prop, _prop, strlen(_prop));
	
	//DEBUGPRINT("deserialize_proposal %s<<\n", prop);
	
	strtok(prop, ":");
	msg->server_id = atoi(strtok(NULL, ":"));
	msg->view = atoi(strtok(NULL, ":"));
	msg->seq = atoi(strtok(NULL, ":"));
	
	tmp = strtok(NULL, ":");
	msg->update = (char *)malloc(strlen(tmp) + 1);
	bzero((char*)msg->update,strlen(tmp)+1);
	strncpy(msg->update, tmp, strlen(tmp));
	
	free(prop);
	
	return msg;	
}


struct msg_accept *create_accept(int server_id, int view, int seq) {
	struct msg_accept *msg;
	msg = (struct msg_accept *) malloc(sizeof(struct msg_accept));
	
	msg->server_id = server_id;
	msg->view = view;
	msg->seq = seq;
	
	return msg;
}

char *serialize_accept(struct msg_accept *accept) {
	char *msg;
	int len = 3 * INT_SIZE + strlen(TITLE_PREP) + 5;
	//allocating 4 chars for each integer
	
	msg = (char *) malloc(len); 
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:%d:%d", TITLE_ACCEPT, accept->server_id, accept->view, accept->seq); 
	
	return msg;
}

struct msg_accept *deserialize_accept(char *_accept) {
	char *tmp;
	char *accept;
	struct msg_accept *msg;

	accept = (char *) malloc(strlen(_accept) + 1);
	bzero((char *) accept, strlen(_accept) + 1);
	strncpy(accept, _accept, strlen(_accept));

	tmp = strtok(accept, ":");
	tmp = strtok(NULL, ":"); 

	msg = (struct msg_accept *) malloc(sizeof(struct msg_accept));
	msg->server_id = atoi(tmp);
	msg->view = atoi(strtok(NULL, ":"));
	msg->seq = atoi(strtok(NULL, ":"));
	
	free(accept);
	
	return msg;
}

struct msg_globally_ordered_update *create_gou(int server_id, int seq, char *update) {

	//DEBUGPRINT("Received GOU Create Update %s\n",update);

	struct msg_globally_ordered_update *msg;
	
	msg = (struct msg_globally_ordered_update *) malloc(sizeof(struct msg_globally_ordered_update));
	msg->server_id = server_id;
	msg->seq = seq;
	msg->update = (char *) malloc(strlen(update)+1);
	bzero((char*)msg->update,strlen(update)+1);
	strncpy(msg->update, update, strlen(update));
	
	return msg;
}

char *serialize_gou(struct msg_globally_ordered_update *gou) {
	char *msg;
	int len = 3 * INT_SIZE + strlen(TITLE_GOU) + strlen(gou->update) + 5;
	//allocating 4 chars for each integer
	
	msg = (char *) malloc(len); 
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:%d:%s", TITLE_GOU, gou->server_id, gou->seq, gou->update); 
	
	return msg;
}

struct msg_globally_ordered_update *deserialize_gou(char *_gou) {
	struct msg_globally_ordered_update *msg;
	char *tmp;
	char *gou;
	
	gou = (char *) malloc(strlen(_gou) + 1);
	bzero((char *) gou, strlen(_gou) + 1);
	strncpy(gou, _gou, strlen(_gou));
	
	msg = (struct msg_globally_ordered_update *) malloc(sizeof(struct msg_globally_ordered_update));
	
	strtok(gou, ":");
	msg->server_id = atoi(strtok(NULL, ":"));
	msg->seq = atoi(strtok(NULL, ":"));
	
	tmp = strtok(NULL, ":");
	msg->update = (char *)malloc(strlen(tmp) + 1);
	bzero((char*)msg->update,strlen(tmp)+1);
	strncpy(msg->update, tmp, strlen(tmp));
	
	free(gou);
	
	return msg;	
}


struct msg_prepare_ok *create_prepare_ok(int server_id, int view) {
	struct msg_prepare_ok *po;
	struct global_history *tmp;
	struct msg_globally_ordered_update *tmp_gou; 
	struct msg_proposal *tmp_prop;
	struct list_head *pos;
		
	po = (struct msg_prepare_ok *) malloc(sizeof(struct msg_prepare_ok));
	po->server_id = server_id;
	po->view = view;
	
	INIT_LIST_HEAD(&po->pl.list);
	INIT_LIST_HEAD(&po->goul.list);

	//Traverse global history	
	list_for_each(pos, &history.list) {
		tmp = list_entry(pos, struct global_history, list);
		if(tmp->seq > local_aru) { //for each i > local_aru
			if(tmp->gou != NULL) { //There is a gou
				//Create a copy of the gou
				tmp_gou = create_gou(tmp->gou->server_id, 
									 tmp->gou->seq,
									 tmp->gou->update);
	
				//DEBUGPRINT("PO:Adding gou entry", NULL);
				list_add_tail(&(tmp_gou->list), &(po->goul.list));
			} 
			
			if (tmp->prop != NULL) { //There is a proposal
				//Create a copy of proposal
				tmp_prop = create_proposal(tmp->prop->server_id,
									   tmp->prop->view,
									   tmp->prop->seq,
									   tmp->prop->update);
				//DEBUGPRINT("PO:Adding prop entry", NULL);
				list_add_tail(&(tmp_prop->list), &(po->pl.list));
			}
		}
	}
	
	return po;	
}

char *serialize_prepare_ok(struct msg_prepare_ok *po) {
	struct list_head *pos;
	struct msg_globally_ordered_update *tmp_gou; 
	struct msg_proposal *tmp_prop;
	char *msg;
	char *tmp_msg;
	char *swp_msg;
	char *list_msg;
	char *prop_list_msg;
	int len;
	
	len = 2 * INT_SIZE + strlen(TITLE_PREP_OK) + 20;
	msg = (char *) malloc(len);
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:%d", TITLE_PREP_OK, po->server_id, po->view);
	
	//Serialize gou list
	list_msg = NULL;
	list_for_each(pos, &po->goul.list) {
		tmp_gou = list_entry(pos, struct msg_globally_ordered_update, list);
		tmp_msg = serialize_gou(tmp_gou);

		if(list_msg == NULL) {
			list_msg = tmp_msg;
		} else {
			//Copy to msg
			len = strlen(list_msg) + strlen(tmp_msg) + 2;
			swp_msg = (char *) malloc(len);
			sprintf(swp_msg, "%s;%s", list_msg, tmp_msg);
			list_msg = swp_msg;
		}
	}
	
	//serialize proposal list
	prop_list_msg = NULL;

	list_for_each(pos, &po->pl.list) {
		tmp_prop = list_entry(pos, struct msg_proposal, list);
		tmp_msg = serialize_proposal(tmp_prop);
	
		if(prop_list_msg == NULL) {
			prop_list_msg = tmp_msg;
		} else {
			//Copy to msg
			len = strlen(prop_list_msg) + strlen(tmp_msg) + 2;
			swp_msg = (char *) malloc(len);
			sprintf(swp_msg, "%s;%s", prop_list_msg, tmp_msg);
			prop_list_msg = swp_msg;
		}

	}
	
	if(list_msg == NULL) {
		list_msg = (char *) malloc(5);
		bzero((char *)list_msg, 5);
		strncpy(list_msg, "NONE", 4);
	}
	
	if(prop_list_msg == NULL) {
		prop_list_msg = (char *) malloc(5);
		bzero((char *)prop_list_msg, 5);
		strncpy(prop_list_msg, "NONE", 4);		
	}
	
	len = strlen(msg) + strlen(list_msg) + strlen(prop_list_msg) + 3;
	swp_msg = (char *) malloc(len);
	bzero((char *) swp_msg, len);
	
	sprintf(swp_msg, "%s|%s|%s", msg, list_msg, prop_list_msg);
	
	free(list_msg);
	
	
	return swp_msg;

}

struct tmp_str_list {
	char *val;
	struct list_head list;
};

struct msg_prepare_ok *deserialize_prepare_ok(char *_po) {
	struct msg_prepare_ok *msg;
	struct msg_proposal *tmp_prop;
	struct msg_globally_ordered_update *tmp_gou;
	char *tmp;
	char *tmp_po;
	char *tmp_goul;
	char *tmp_pl;
	char *po;
	struct tmp_str_list ts_list;
	struct tmp_str_list *tmp_entry;
	struct list_head *pos, *q;
	
	
	po = (char *) malloc(strlen(_po) + 1);
	bzero((char *) po, strlen(_po) + 1);
	strncpy(po, _po, strlen(_po));
	
	msg = (struct msg_prepare_ok *) malloc(sizeof(struct msg_prepare_ok));
	
	tmp_po = strtok(po, "|");
	tmp_goul = strtok(NULL,"|");
	tmp_pl = strtok(NULL, "|");
	
//	DEBUGPRINT("DS_PO: %s, %s, %s", tmp_po, tmp_goul, tmp_pl);
	
	strtok(tmp_po, ":");
	msg->server_id = atoi(strtok(NULL, ":"));
	msg->view = atoi(strtok(NULL, ":"));
	INIT_LIST_HEAD(&msg->pl.list);
	INIT_LIST_HEAD(&msg->goul.list);

	INIT_LIST_HEAD(&ts_list.list);	
	
	if(tmp_goul != NULL && strlen(tmp_goul) > 0 && strcmp("NONE", tmp_goul) != 0) {
		if(strstr(tmp_goul, ";") != NULL) {
			tmp = strtok(tmp_goul, ";");
			while(tmp != NULL) {
				
				tmp_entry = (struct tmp_str_list *) malloc(sizeof(struct tmp_str_list));
				tmp_entry->val = tmp;
				list_add_tail(&(tmp_entry->list), &(ts_list.list));
				
				tmp = strtok(NULL, ";");
			}
			
			//Once we have all the entries we will deserialize them
			list_for_each_safe(pos, q, &ts_list.list) {
				tmp_entry = list_entry(pos, struct tmp_str_list, list);
				tmp_gou = deserialize_gou(tmp_entry->val);
				list_add_tail(&(tmp_gou->list), &(msg->goul.list));
				
				list_del(pos);
				free(tmp_entry);
			}
		} else {
			//There's only one entry
			tmp_gou = deserialize_gou(tmp_goul);
			list_add_tail(&(tmp_gou->list), &(msg->goul.list));
		}
	}

	

	if(tmp_pl != NULL && strlen(tmp_pl) > 0 && strcmp("NONE", tmp_pl) != 0) {

		if(strstr(tmp_pl, ";") != NULL) {
			tmp = strtok(tmp_pl, ";");
			while(tmp != NULL) {
				
				tmp_entry = (struct tmp_str_list *) malloc(sizeof(struct tmp_str_list));
				tmp_entry->val = tmp;
				list_add_tail(&(tmp_entry->list), &(ts_list.list));
				
				tmp = strtok(NULL, ";");
			}
			
			//Once we have all the entries we will deserialize them
			list_for_each_safe(pos, q, &ts_list.list) {
				tmp_entry = list_entry(pos, struct tmp_str_list, list);
				tmp_prop = deserialize_proposal(tmp_entry->val);
				list_add_tail(&(tmp_prop->list), &(msg->pl.list));
				
				list_del(pos);
				free(tmp_entry);
			}
		} else {
			//There's only one entry
			tmp_prop = deserialize_proposal(tmp_pl);
			list_add_tail(&(tmp_prop->list), &(msg->pl.list));
		}
	}
	
	free(po);
	
	return msg;
}


int get_message_type(char *msg) {
	char *type;
	char *tmp;
	int ret_val = -1;
	
	//First make a copy
	tmp = (char *) malloc(strlen(msg) + 1);
	bzero((char *) tmp, strlen(msg) + 1);
	strncpy(tmp, msg, strlen(msg));
	
	type = strtok(tmp, ":");
	
	if(strcmp(type, TITLE_VC) == 0) {
		ret_val = VC;
	} else if(strcmp(type, TITLE_VC_PROOF) == 0) {
		ret_val = VC_PROOF;
	} else if(strcmp(type, TITLE_PREP) == 0) {
		ret_val = PREP;
	} else if(strcmp(type, TITLE_PREP_OK) == 0) {
		ret_val = PREP_OK;
	} else if(strcmp(type, TITLE_PROP) == 0) {
		ret_val = PROP;
	} else if(strcmp(type, TITLE_ACCEPT) == 0) {
		ret_val = ACCEPT;
	} else if(strcmp(type, TITLE_GOU) == 0) {
		ret_val = GOU;
	} else if(strcmp(type, TITLE_HOST_ID) == 0) {
		ret_val = HOST_ID;
	} else if(strcmp(type, TITLE_CU) == 0) {
		ret_val = CU;
	}
	
	free(tmp);
	return ret_val;
	

}

int conflict(char *msg) {
	
	int type;
	struct msg_view_change *msg_vc;
	struct msg_vc_proof *msg_vc_proof;

	//TODO
	type = get_message_type(msg);
	switch(type) {
		case VC:
			break;
		case VC_PROOF:
			break;
		case PREP:
			break;
		case PREP_OK:
			break;
		case PROP:
			break;
		case ACCEPT:
			break;
	}
	
	return 0;
}

void update_data_structures(char *msg) {
	int type;

	type = get_message_type(msg);
	
	switch(type) {
		case VC:
			add_vc(deserialize_view_change(msg));
			break;
		case VC_PROOF:
			break;
		case PREP:
			prep = deserialize_prepare(msg);
			break;
		case PREP_OK:
			add_prep_ok(deserialize_prepare_ok(msg));
			break;
		case PROP:
			add_proposal(deserialize_proposal(msg));
			break;
		case ACCEPT:
			add_accept(deserialize_accept(msg));
			break;
		case GOU:
			//DEBUGPRINT("apply_ds: GOU\n", NULL);
			add_gou(deserialize_gou(msg));
			break;
	}
}


void add_vc(struct msg_view_change *msg) {
	struct msg_view_change *tmp;
	struct list_head *pos;
	
	list_for_each(pos, &vc_list.list) {
		tmp = list_entry(pos, struct msg_view_change, list);
		if(tmp->server_id == msg->server_id) {
			return;
		}
	}
	
	//This server is not in the list
	list_add_tail(&(msg->list), &(vc_list.list));
}

void clear_vc_list() {
	struct msg_view_change *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &vc_list.list){
		 tmp = list_entry(pos, struct msg_view_change, list);
		 list_del(pos);
		 free(tmp);
	}
}

void add_prep_ok(struct msg_prepare_ok *msg) {
	struct msg_prepare_ok *tmp;
	struct msg_proposal *tmp_prop;
	struct msg_globally_ordered_update *tmp_gou;
	struct list_head *pos;
	
	list_for_each(pos, &prep_ok_list.list) {
		tmp = list_entry(pos, struct msg_prepare_ok, list);
		if(tmp->server_id == msg->server_id) {
			return;
		}
	}
	
	//This server is not in the list
	list_add_tail(&(msg->list), &(prep_ok_list.list));
	
	//Add each entry in pl and goul
	list_for_each(pos, &msg->pl.list) {
		tmp_prop = list_entry(pos, struct msg_proposal, list);
		add_proposal(tmp_prop);
	}
	list_for_each(pos, &msg->goul.list) {
		tmp_gou = list_entry(pos, struct msg_globally_ordered_update, list);
		add_gou(tmp_gou);
	}

}

void clear_prep_ok_list() {
	struct msg_prepare_ok *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &prep_ok_list.list){
		 tmp = list_entry(pos, struct msg_prepare_ok, list);
		 list_del(pos);
		 free(tmp);
	}
}


void add_client_update(struct msg_client_update *cu) {
	//Duplicate
	struct msg_client_update *tmp = create_client_update(cu->client_id, cu->server_id, cu->timestamp, cu->update);
	list_add_tail(&(tmp->list), &(update_queue.list));
}

void clear_update_queue() {
	struct msg_client_update *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &update_queue.list){
		 tmp = list_entry(pos, struct msg_client_update, list);
		 list_del(pos);
		 free(tmp);
	}
}

int in_update_queue(struct msg_client_update *cu){

	struct msg_client_update *tmp;
	struct list_head *pos;
	list_for_each(pos, &update_queue.list){
		 tmp = list_entry(pos, struct msg_client_update, list);
		 if(tmp->client_id == cu->client_id)
		 	if(tmp->server_id == cu->server_id)
		 		if(tmp->timestamp == cu->timestamp)
		 			if(!strcmp(tmp->update, cu->update))
		 				return 1;
	}
	return 0;
}

struct msg_client_update* get_from_update_queue(struct msg_client_update *cu){

	struct msg_client_update *tmp;
	struct list_head *pos;
	list_for_each(pos, &update_queue.list){
		 tmp = list_entry(pos, struct msg_client_update, list);
		 if(tmp->client_id == cu->client_id)
		 	if(tmp->server_id == cu->server_id)
		 		if(tmp->timestamp == cu->timestamp)
		 			if(!strcmp(tmp->update, cu->update))
		 				return tmp;
	}
	return NULL;
}

int update_queue_empty(){
	//DEBUGPRINT("Update Queue Empty\n",NULL);
	return list_empty(&update_queue.list);
}

//pending updates access functions
void add_pending_update(struct msg_client_update *cu) {
	//DEBUGPRINT("Adding The Update\n",NULL);
	struct msg_client_update* tmp = create_client_update(cu->client_id, cu->server_id, cu->timestamp, cu->update);
	list_add_tail(&(tmp->list), &(pending_updates.list));
}

void add_to_pending_updates(struct msg_client_update *cu){

	struct client_ts *tmp;
	struct list_head *pos, *q;
	/*
	list_for_each_safe(pos, q, &pending_updates.list){
		tmp = list_entry(pos, struct client_ts, list);
		if(tmp->client_id == cu->client_id){
			//NOT SURE ABOUT THIS
			tmp->timestamp = cu->timestamp;
			tmp->list = cu->list;
			//SET UPDATE TIMER
			sync();
			break;
		}
	}
	*/
	//TODO Add update timer
	//Client was not in the list
	add_pending_update(cu);
}

struct client_ts* get_from_pending_updates(struct msg_client_update *cu){
	
	struct client_ts *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &pending_updates.list){
		tmp = list_entry(pos, struct client_ts, list);
		if(tmp->client_id == cu->client_id){
			return tmp;
		}
	}
	return NULL;
}

struct msg_client_update* get_from_pending_updates_message(char* msg){
	
	struct msg_client_update *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &pending_updates.list){
		tmp = list_entry(pos, struct msg_client_update, list);
		if(!strcmp(tmp->update,msg)){
			list_del(pos);
			return tmp;
		}
	}
	return NULL;
}

void clear_pending_updates() {
	struct msg_client_update *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &pending_updates.list){
		 tmp = list_entry(pos, struct msg_client_update, list);
		 list_del(pos);
		 free(tmp);
	}
}

void update_last_executed(int client_id, int timestamp) {

	struct client_ts *tmp;
	struct list_head *pos, *q;
	int updated = 0;
	list_for_each_safe(pos, q, &last_executed.list){
		 tmp = list_entry(pos, struct client_ts, list);
		 if(tmp->client_id == client_id) {
		 	//Update entry
		 	tmp->timestamp = timestamp;
		 	updated = 1;
		 	break;
		 }
	}
	
	if(!updated) { //Client was not in the list
		tmp = (struct client_ts *) malloc(sizeof(struct client_ts));
		tmp->client_id = client_id;
		tmp->timestamp = timestamp;
		list_add_tail(&(tmp->list), &(last_executed.list));
	}
}

struct client_ts* get_from_last_executed(struct msg_client_update *cu){
	struct client_ts *tmp;
	struct list_head *pos;
	list_for_each(pos, &last_executed.list){
		tmp = list_entry(pos, struct client_ts, list);
		if(tmp->client_id == cu->client_id)
			return tmp;
	}
	return NULL;
}



void clear_last_executed() {
	struct client_ts *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &last_executed.list){
		 tmp = list_entry(pos, struct client_ts, list);
		 list_del(pos);
		 free(tmp);
	}
}

void update_last_enqueued(int client_id, int timestamp) {
	struct client_ts *tmp;
	struct list_head *pos, *q;
	int updated = 0;
	list_for_each_safe(pos, q, &last_enqueued.list){
		 tmp = list_entry(pos, struct client_ts, list);
		 if(tmp->client_id == client_id) {
		 	//Update entry
		 	tmp->timestamp = timestamp;
		 	updated = 1;
		 }
	}
	
	if(!updated) { //Client was not in the list
		tmp = (struct client_ts *) malloc(sizeof(struct client_ts));
		tmp->client_id = client_id;
		tmp->timestamp = timestamp;
		list_add_tail(&(tmp->list), &(last_enqueued.list));
	}
}

struct client_ts* get_from_last_enqueued(struct msg_client_update *cu){
	struct client_ts *tmp;
	struct list_head *pos;
	list_for_each(pos, &last_enqueued.list){
		tmp = list_entry(pos, struct client_ts, list);
		if(tmp->client_id == cu->client_id)
			return tmp;
	}
	return NULL;
}

void clear_last_enqueued() {
	struct client_ts *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &last_enqueued.list){
		 tmp = list_entry(pos, struct client_ts, list);
		 list_del(pos);
		 free(tmp);
	}
}

int enqueue_update(struct msg_client_update *u){

	struct client_ts *tmp = NULL;
	struct list_head *pos;
	list_for_each(pos, &last_executed.list){
		 tmp = list_entry(pos, struct client_ts, list);
		 if(tmp->client_id == u->client_id) {
		 	if(u->timestamp <= tmp->timestamp) {
 				//DEBUGPRINT("enqueue_update: 0\n", NULL);
		 		return 0;
		 	}
		 }
	}
	/*
	list_for_each(pos, &last_enqueued.list){
		tmp = list_entry(pos, struct client_ts, list);
		if(tmp->client_id == u->client_id){
			if(u->timestamp <= tmp->timestamp) {
 				//DEBUGPRINT("enqueue_update: 0\n", NULL);
				return 0;
			}else{
				//add_client_update(u);
				tmp->timestamp = u->timestamp;
				break;
			}
		}
	}*/
	
	add_client_update(u);
	update_last_enqueued(u->client_id, u->timestamp);
 	//DEBUGPRINT("enqueue_update: 1: success\n", NULL);
	return 1;
	
}

void enqueue_unbound_pending_updates(){
	
	struct msg_client_update *tmp;
	struct list_head *pos;
	list_for_each(pos, &pending_updates.list){
		tmp = list_entry(pos, struct msg_client_update, list);
		if(!in_global_history(tmp->timestamp) && !in_update_queue(tmp))
			enqueue_update(tmp);
	}
}

void remove_bound_updates_from_queue(){

	//DEBUGPRINT("Trying To Remove Bound Updates\n",NULL);

	struct msg_client_update *tmp;
	struct list_head *pos, *q;
	list_for_each_safe(pos, q, &update_queue.list){
		 tmp = list_entry(pos, struct msg_client_update, list);
		 int a = 0;
		 
		 if(in_global_history(tmp->timestamp))
		 	a = 1;
		 	
		 if(tmp->timestamp <= get_from_last_executed(tmp)->timestamp)
		 	a = 1;
		 	
		 if(tmp->timestamp <= get_from_last_enqueued(tmp)->timestamp &&
		 		tmp->server_id != my_id)
		 	a = 1;
		 	
		 if(a == 1){
		 	//DEBUGPRINT("Removing Update %s : %d\n",tmp->update,tmp->timestamp);
		 	list_del(pos);
		 	if(tmp->timestamp > get_from_last_enqueued(tmp)->timestamp)
		 		get_from_last_enqueued(tmp)->timestamp = tmp->timestamp;
		 }
	}
}

//Global history functions

void add_proposal(struct msg_proposal *_prop) {
	struct list_head *apos, *aq;
	struct msg_accept *atmp;
	struct global_history *tmp;
	struct msg_proposal *prop;
	
	prop = create_proposal(_prop->server_id,_prop->view,_prop->seq,_prop->update);

	//DEBUGPRINT("Adding a proposal : server: %d, view: %d, seq: %d, update: %s", 
			//prop->server_id, prop->view, prop->seq, prop->update);
	tmp = get_history_entry(prop->seq);
	
	if(tmp->gou != NULL) {
		//DEBUGPRINT("Already Ordered\n",NULL);
		return; //Already ordered
	}
	
	if(tmp->prop != NULL) {
		if(prop->view > tmp->prop->view) { //This proposal is from a new view
			//DEBUGPRINT("This Proposal from a New View\n",NULL);
			tmp->prop = prop; // update history entry
			//Clear accepts
			list_for_each_safe(apos, aq, &tmp->accepts.list){
				 atmp = list_entry(apos, struct msg_accept, list);
				 list_del(apos);
				 free(atmp);
			}
		}
	} else {
		//DEBUGPRINT("Updating the Proposal in History Entry\n",NULL);
		tmp->prop = prop;
	}
}

void add_gou(struct msg_globally_ordered_update *gou) {
	struct global_history *tmp;
	
	tmp = get_history_entry(gou->seq);
	if(tmp->gou == NULL) {
		//DEBUGPRINT("Adding gou : %d : %s\n", gou->seq, gou->update);
		tmp->gou = gou;
	}
}

void add_accept(struct msg_accept *accept) {
	struct global_history *tmp;
	struct list_head *pos;
	struct msg_accept *tmp_accept;
	int count = 0;
	
	//DEBUGPRINT("Adding the Accept\n",NULL);
	
	tmp = get_history_entry(accept->seq);
	if(tmp->gou != NULL) {
		//DEBUGPRINT("Already Ordered Accept\n",NULL);
		return; //Already ordered
	}
	
	list_for_each(pos, &tmp->accepts.list) {
		tmp_accept = list_entry(pos, struct msg_accept, list);
		if(tmp_accept->server_id == accept->server_id) {
			//DEBUGPRINT("Already Have This Update\n",NULL);
			return; //We already have this update
		}
		count ++;
		//DEBUGPRINT("We have %d Accepts, Need %d\n",count,host_count/2);
		if(count >= ((host_count/2) + 1)) {
			//DEBUGPRINT("We Have Enough Accepts\n",NULL);
			return; //We have enough accepts
		}
	}
	//DEBUGPRINT("Update Added Successfully\n",NULL);
	//This is an update we need : so we add to list
	list_add_tail(&(accept->list), &(tmp->accepts.list));
}

/*
If there's no entry for the given seq 
a new one will be created
*/
struct global_history *get_history_entry(int seq) {
	struct global_history *tmp;
	struct list_head *pos;
	struct global_history *entry;	

	//DEBUGPRINT("getting history entry for %d\n", seq);
	entry = NULL;
	list_for_each(pos, &history.list) {
		tmp = list_entry(pos, struct global_history, list);
		if(tmp->seq == seq) {
			entry = tmp;
			break;
		}
	}
	
	if(entry == NULL) {
		//Create a new one and add to list
		//DEBUGPRINT("Creating New History Entry\n",NULL);
		entry = (struct global_history *) malloc(sizeof(struct global_history));
		entry->seq = seq;
		entry->prop = NULL;
		entry->gou = NULL;
		INIT_LIST_HEAD(&entry->accepts.list);
		list_add_tail(&(entry->list), &(history.list));
	}
	
	return entry;
}

char* get_global_history_proposal(int seq){

	//DEBUGPRINT("GET GLOBAL HISTORY PROPOSAL\n",NULL);
	struct global_history *tmp;
	struct list_head *pos;
	list_for_each(pos, &history.list) {
		tmp = list_entry(pos, struct global_history, list);
		if(tmp->seq == seq) {
		
			if(tmp->prop != NULL)
				return tmp->prop->update;
		}
	}
	return NULL;
}

int in_global_history(int seq){

	struct global_history *tmp;
	struct list_head *pos;
	list_for_each(pos, &history.list) {
		tmp = list_entry(pos, struct global_history, list);
		if(tmp->seq == seq && tmp->gou != NULL) {
			return 1;
		}
	}
	return 0;
}

void clear_history() {
	struct list_head *pos, *q;
	struct global_history *tmp;	

	list_for_each_safe(pos, q, &history.list) {
		 tmp = list_entry(pos, struct global_history, list);
		 list_del(pos);
		 free(tmp);
	}
}

char *host_id_response() {
	char *ret;
	ret = malloc(10);
	bzero((char *) ret, 10);
	
	sprintf(ret, "%d", my_id);
	return ret;
}

char* serialize_gh(struct global_history* gh){

	struct list_head *pos;
	struct msg_proposal *tmp_prop;
	char *msg;
	char *tmp_msg;
	char *acc;
	char *swp_msg;
	char *list_msg;
	char *prop_list_msg;
	int len;
	
	len = 2 * INT_SIZE + strlen(TITLE_GH) + 20;
	msg = (char *) malloc(len);
	bzero((char *) msg, len);
	
	sprintf(msg, "%s:%d:", TITLE_GH, gh->seq);
	
	char* prop = NULL;
	if(gh->prop == NULL)
		prop = "NONE";
	else
		prop = serialize_proposal(gh->prop);
	
	len = strlen(msg) + strlen(prop) + 2;
	
	tmp_msg = (char*) malloc(len);
	bzero((char*)tmp_msg,len);
	
	sprintf(tmp_msg,"%s|%s",msg,prop);
	
	//Serialize gou list
	list_msg = NULL;
	list_for_each(pos, &gh->accepts.list) {
		struct msg_accept *tmp_gou = list_entry(pos, struct msg_accept, list);
		acc = serialize_accept(tmp_gou);

		if(list_msg == NULL) {
			list_msg = acc;
		} else {
			//Copy to msg
			len = strlen(list_msg) + strlen(acc) + 2;
			swp_msg = (char *) malloc(len);
			sprintf(swp_msg, "%s;%s", list_msg, acc);
			list_msg = swp_msg;
		}
	}
	
	if(list_msg == NULL) {
		list_msg = (char *) malloc(5);
		bzero((char *)list_msg, 5);
		strncpy(list_msg, "NONE", 4);
	}
	
	char* gou = NULL;
	
	if(gh->gou != NULL){
		gou = serialize_gou(gh->gou);
	}
	
	if(gou == NULL) {
		gou = (char *) malloc(5);
		bzero((char *)gou, 5);
		strncpy(gou, "NONE", 4);
	}
	
	len = strlen(tmp_msg) + strlen(list_msg) + strlen(gou) + 3;
	swp_msg = (char *) malloc(len);
	bzero((char *) swp_msg, len);
	
	sprintf(swp_msg, "%s|%s|%s", tmp_msg, list_msg, gou);
	
	free(tmp_msg);
	
	return swp_msg;
}


struct global_history* deserialize_gh(char* ghstr){

	//GLOBAL_HISTORY:20:|ACCEPT:14:0:20;ACCEPT:7:0:20|GOU:14:20:Update10
	
	struct global_history *hist;
	hist = (struct global_history*) malloc(sizeof(struct global_history));
	INIT_LIST_HEAD(&hist->accepts.list);
	
	char* copy = (char*) malloc(strlen(ghstr)+1);
	bzero(copy,strlen(ghstr)+1);
	strncpy(copy,ghstr,strlen(ghstr));
	
	char* tmp = strtok(copy,"|");
	
	
	//Copy Tmp into SEQ 
	char* seqstr = (char*) malloc(strlen(tmp)+1);
	bzero((char*)seqstr,strlen(tmp)+1);
	strncpy(seqstr,tmp,strlen(tmp));
	
	tmp = strtok(NULL,"|");
	char* propstr = (char*) malloc(strlen(tmp)+1);
	bzero((char*)propstr,strlen(tmp)+1);
	strncpy(propstr,tmp,strlen(tmp));
	
	tmp = strtok(NULL,"|");
	char* alist = (char*) malloc(strlen(tmp)+1);
	bzero((char*)alist,strlen(tmp)+1);
	strncpy(alist,tmp,strlen(tmp));
	
	tmp = strtok(NULL,"|");
	char* goustr = (char*) malloc(strlen(tmp)+1);
	bzero((char*)goustr,strlen(tmp)+1);
	strncpy(goustr,tmp,strlen(tmp));
	
	
	
	if(strcmp("NONE",alist) != 0){
		tmp = strtok(alist, ";");
	while(tmp != NULL) {
		struct msg_accept *acctmp = deserialize_accept(tmp);
		//fprintf(stderr,"READ ACCEPT: %s\n",tmp);
		list_add_tail(&(acctmp->list), &(hist->accepts.list));
		tmp = strtok(NULL,";");
	}
	}
	
	
	
	strtok(seqstr,":");
	char* seqchr = strtok(NULL,":");
	int seq = atoi(seqchr);

	hist->seq = seq;
	hist->prop = NULL;
	
	if(strcmp("NONE",propstr) != 0){
	
	hist->prop = deserialize_proposal(propstr);
	
	}
	
	hist->gou = NULL;
	if(strcmp("NONE",goustr) != 0){
	struct msg_globally_ordered_update *gou = deserialize_gou(goustr);
	
	hist->gou = gou;
	}
	
	return hist;
}

